using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Gj.ILRuntimeExt;
using SimpleJSON;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace Gj
{
    [InitializeOnLoad]
    public class ILRuntimeEditor
    {
        internal static string targetDir = "Project";
        internal static string codePath = "Assets/Projects";
        internal static string configuration = "Debug";
        internal const string sourcePath = "Assets/StreamingAssets/Project";
        internal static Dictionary<string, string> projects = new Dictionary<string, string>();
        private static List<Type> types = new List<Type>();
        static ILRuntimeEditor(){
            // 自动解析项目
            // DirectoryInfo rootDir = Directory.GetCurrentDirectory();
            string targetDir = Path.Combine(Environment.CurrentDirectory, codePath);
            if (Directory.Exists(targetDir))
            {
                DirectoryInfo dir = new DirectoryInfo(targetDir);
                foreach (DirectoryInfo dChild in dir.GetDirectories("*"))
                {
                    if (File.Exists(dChild.FullName+"/"+dChild.Name+".csproj")){
                        projects.Add(dChild.Name, dChild.FullName);
                    }
                    // UnityEngine.Debug.Log(dChild.FullName);
                }
            }

            // 注册CLR绑定
            //在List中添加你想进行CLR绑定的类型
            RegisterCLRBinding(typeof(int));
            RegisterCLRBinding(typeof(float));
            RegisterCLRBinding(typeof(long));
            RegisterCLRBinding(typeof(object));
            RegisterCLRBinding(typeof(string));
            RegisterCLRBinding(typeof(Array));
            RegisterCLRBinding(typeof(Dictionary<string, int>));
            RegisterCLRBinding(typeof(JSONObject));
            RegisterCLRBinding(typeof(JSONArray));
            //所有ILRuntime中的类型，实际上在C#运行时中都是ILRuntime.Runtime.Intepreter.ILTypeInstance的实例，
            //因此List<A> List<B>，如果A与B都是ILRuntime中的类型，只需要添加List<ILRuntime.Runtime.Intepreter.ILTypeInstance>即可
            RegisterCLRBinding(typeof(Dictionary<ILRuntime.Runtime.Intepreter.ILTypeInstance, int>));
            RegisterCLRBinding(typeof(List<ILRuntime.Runtime.Intepreter.ILTypeInstance>));
        }

        internal static void Compile(string projectName, string projectPath, string targetPath)
        {
            using (Process myPro = new Process())
            {
                string p = projectPath + @"/" + projectName + @".csproj /nologo /v:m";
                if (configuration != "")
                {
                    p += " /p:Configuration=" + configuration;
                }
                
                Debug.Log(p);
#if UNITY_EDITOR_OSX
                    // ProcessStartInfo psi = new ProcessStartInfo(@"/Applications/Unity/Hub/Editor/"+Application.unityVersion+"/Unity.app/Contents/NetCoreRuntime/dotnet","build "+p);
                    ProcessStartInfo psi = new ProcessStartInfo(@"/usr/local/share/dotnet/dotnet","build "+p);
                    // psi.Environment.Add("FrameworkPathOverride", "/Library/Frameworks/Mono.framework/Versions/Current");
#elif UNITY_EDITOR_WIN
                    ProcessStartInfo psi = new ProcessStartInfo(@"D:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\bin\msbuild.exe", p);

#endif
                // string p = projectPath + @"\" + projectName + @".csproj /build " + configuration;
                // ProcessStartInfo psi = new ProcessStartInfo(@"D:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com", p);
                // UnityEngine.Debug.Log(p);
                //指定启动进程是调用的应用程序和命令行参数
                psi.CreateNoWindow = true;
                psi.ErrorDialog = true;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardInput = true;
                psi.RedirectStandardError = true;
                psi.UseShellExecute = false;
                psi.WorkingDirectory = Environment.CurrentDirectory;
                psi.StandardOutputEncoding = Encoding.UTF8;
                psi.StandardErrorEncoding = Encoding.UTF8;
                myPro.StartInfo = psi;
                myPro.Start();
                Debug.Log(EncodingConvert(myPro.StandardOutput.CurrentEncoding, Encoding.UTF8, myPro.StandardOutput.ReadToEnd()));
                Debug.Log(EncodingConvert(myPro.StandardOutput.CurrentEncoding, Encoding.UTF8, myPro.StandardError.ReadToEnd()));
                // result = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(result));
                // UnityEngine.Debug.Log(result);
                myPro.WaitForExit();
                myPro.Close();
            }
            
            // 移除obj文件，避免Unity加载
            string objFolderPath = Path.Combine(projectPath, "obj");
            FileTools.DeleteFolder(objFolderPath);

            // 将stream中的文件移动到targetPath
            string srcFolderPath = Path.Combine(Environment.CurrentDirectory, sourcePath);
            if (Directory.Exists(srcFolderPath))
            {
                if (!Directory.Exists(targetPath))
                {
                    Directory.CreateDirectory(targetPath);
                }
                Debug.Log(srcFolderPath + " -> " + targetPath);
                DirectoryInfo folder = new DirectoryInfo(srcFolderPath);
                foreach (FileInfo fChild in folder.GetFiles())
                {
                    // Debug.Log(fChild.Name+"->"+Path.GetExtension(fChild.Name));
                    if (Path.GetExtension(fChild.Name) != ".dll") continue;
                    Debug.Log(fChild.Name);
                    var path = Path.Combine(targetPath,
                        Path.GetFileNameWithoutExtension(fChild.Name) + Projects.Extend);
                    if (File.Exists(path))
                    {
                        File.Delete(path);
                    }
                    fChild.MoveTo(path);
                }
                FileTools.DeleteFolder(srcFolderPath);
            }
            // 移除obj文件，避免Unity加载
            FileTools.DeleteFolder(objFolderPath);
            
        }
        
        internal static void GenerateCLRBinding()
        {
            ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(types, "Assets/ILRuntime/Generated");
           
            Debug.Log("Generate CLR Binding -> Assets/ILRuntime/Generated");
        }

        static void RegisterCLRBinding(Type t)
        {
            types.Add(t);
        }
        public static string EncodingConvert(Encoding src, Encoding dst, string text)
        {
            var bytes = src.GetBytes(text);
            bytes = Encoding.Convert(src, dst, bytes);
            return dst.GetString(bytes);
        }

    }
}
